set positional-arguments := true
set shell := ["bash", "-c"]

default:
    just --list

build:
    cargo build --release --all-targets

audit:
    cargo audit

audit-fix:
    cargo audit fix

format:
    cargo fmt --check
    npx --yes prettier --check .
    ! command -v nix || nix fmt -- --check .

alias fmt := format

fix:
    cargo clippy --all-targets --no-deps --fix --allow-no-vcs
    just fix-format

fix-format:
    npx --yes prettier --write .
    cargo fmt
    ! command -v nix || nix fmt .

run-local-with-shell:
    #!/usr/bin/env bash
    cargo run --bin custom-connector | ts "custom-connector:" &
    OTLP_ENDPOINT=http://localhost:4317 \
      cargo run --bin dev-auth-webhook | ts "dev-auth-webhook:" &
    RUST_LOG=DEBUG cargo run --bin ddn-engine-local-dev -- \
    --otlp-endpoint http://localhost:4317 \
    --authn-config-path static/auth/auth_config_v3.json \
    --metadata-path static/metadata.json \
    --expose-internal-errors | ts "engine:          " &
    wait

# start all the docker deps for running tests (not engine)
start-docker-test-deps:
    # start connectors and wait for health
    docker compose \
      -f ci.docker-compose.yaml \
      up --wait \
      auth_hook postgres postgres_connector \
      postgres_connector_ndc_v01 custom_connector \
      custom_connector_no_relationships custom_connector_ndc_v01 \
      postgres_promptql \
      pre_ndc_request_plugin_example \
      pre_ndc_response_plugin_example \
      pre_parse_plugin_example \
      test_data_server

# pull / build all docker deps
docker-refresh: stop-docker
    docker compose -f ci.docker-compose.yaml pull \
      postgres_connector \
      postgres_connector_ndc_v01 \
      postgres_promptql
    docker compose -f ci.docker-compose.yaml build \
      custom_connector \
      custom_connector_no_relationships \
      auth_hook \
      pre_ndc_request_plugin_example \
      pre_ndc_response_plugin_example \
      pre_parse_plugin_example

alias refresh-docker := docker-refresh

# stop all the docker deps
stop-docker:
    docker compose -f ci.docker-compose.yaml down -v

# run the tests using local engine (once)
test *ARGS: start-docker-test-deps
    #!/usr/bin/env bash
    if command -v cargo-nextest; then
      # make sure to run doctests too. See: https://github.com/nextest-rs/nextest/issues/16
      cargo nextest run --no-fail-fast "$@" &&\
      cargo test --doc --no-fail-fast "$@"
    else
      # Let's just standardize on this, since it's the configuration we
      # run in CI
      echo "Please 'cargo install cargo-nextest' and re-run this."
      echo "At least on linux it is much faster than just 'cargo test'"
      echo "If you're on mac you can speed things up with: https://nexte.st/docs/installation/macos/"
      exit 1
    fi

# run a watch process that runs the tests locally
watch: start-docker-test-deps
    RUST_LOG=DEBUG \
    cargo watch -i "**/*.snap.new" \
     -x 'nextest run --no-fail-fast' \
     -x 'clippy --no-deps' \
     -x 'run --bin ddn-engine-local-dev -- \
      --otlp-endpoint http://localhost:4317 \
      --authn-config-path static/auth/auth_config_v3.json \
      --metadata-path static/metadata.json \
      --expose-internal-errors'

# check the code is fine
lint:
    cargo clippy --all-targets --no-deps
    ! command -v nix || nix flake check

# ensure we don't have unused dependencies:
machete:
    cargo machete --with-metadata

# update golden tests
update-golden-files: start-docker-test-deps
    UPDATE_GOLDENFILES=1 just test
    just fix-format

update-custom-connector-schema-in-test-metadata:
    docker compose -f ci.docker-compose.yaml up \
    --build --wait custom_connector custom_connector_no_relationships

    just update-schema-in-test-metadata "8102" "v0.2"
    just update-schema-in-test-metadata "8103" "v0.2"

    docker compose -f ci.docker-compose.yaml down

update-postgres-schema-in-test-metadata:
    docker compose -f ci.docker-compose.yaml up \
    --build --wait postgres postgres_connector postgres_connector_ndc_v01

    just update-schema-in-test-metadata "8080" "v0.1"
    just update-schema-in-test-metadata "8082" "v0.2"

    docker compose -f ci.docker-compose.yaml down

update-schema-in-test-metadata PORT NDC_VERSION: && fix-format
    #!/usr/bin/env bash
    set -e

    capabilities_file=$(mktemp)
    curl http://localhost:{{ PORT }}/capabilities | jq > $capabilities_file
    trap 'rm -f "$capabilities_file"' EXIT

    schema_file=$(mktemp)
    curl http://localhost:{{ PORT }}/schema | jq > $schema_file
    trap 'rm -f "$schema_file"' EXIT

    ndc_version="{{ NDC_VERSION }}"

    # Should only be tests that actually talk to the running connector and therefore must be up to date
    test_directories=(./crates/engine/tests/execute)

    find "${test_directories[@]}" -name '*.json' -print0 |
    while IFS= read -r -d '' file; do
      # Check if the file actually contains a custom connector DataConnectorLink
      if jq -e '
        (. | type == "object") and has("subgraphs") and (.subgraphs | length > 0) and (.subgraphs[] | has("objects") and (.objects | length > 0))
        and any(.subgraphs[].objects[]; .kind == "DataConnectorLink" and .definition.url.singleUrl.value == "http://localhost:{{ PORT }}")' "$file" >/dev/null; then

        # Update its schema, capabilities and version
        jq --slurpfile newCapabilities "$capabilities_file" --slurpfile newSchema "$schema_file" --arg ndcVersion "$ndc_version" '
          (.subgraphs[].objects[] | select(.kind == "DataConnectorLink" and .definition.url.singleUrl.value == "http://localhost:{{ PORT }}").definition.schema)
          |= (.capabilities = $newCapabilities[0] | .schema = $newSchema[0] | .version = $ndcVersion)
        ' $file \
        | sponge $file

        echo "Updated $file"
      else
        echo "Skipping $file: Does not appear to be a metadata file with a matching connector"
      fi
    done

# ensures metadata objects in test json have their properties ordered as kind, version, then definition
reorder-json-in-test-metadata: && fix-format
    #!/usr/bin/env bash
    set -e

    # Should only be folders that contain json metadata tests
    test_directories=(./crates/engine/tests/execute ./crates/metadata-resolve/tests)

    find "${test_directories[@]}" -name '*.json' -print0 |
    while IFS= read -r -d '' file; do
      # Check if the file actually contains metadata
      if jq -e '(. | type == "object") and has("subgraphs") and (.subgraphs | length > 0) and (.subgraphs[] | has("objects") and (.objects | length > 0))' "$file" >/dev/null; then

        # Reformat each metadata object so that kind, version, and definition properties come first
        jq '.subgraphs[].objects |= map({ kind: .kind, version: .version, definition: .definition } + .)' $file \
        | sponge $file

        echo "Updated $file"
      else
        echo "Skipping $file: Does not appear to be a metadata file"
      fi
    done

# start docker deps for running engine (rather than running tests) 
start-docker-run-deps:
    # start connectors and wait for health
    docker compose \
      -f ci.docker-compose.yaml \
      up --wait \
      postgres postgres_connector_ndc_v01 custom_connector postgres_promptql 

# run the engine with settings for testing SQL frontend 
run-for-sql METADATA_PATH="static/metadata.json": start-docker-run-deps 
    RUST_LOG=DEBUG cargo run --bin ddn-engine-local-dev -- \
    --otlp-endpoint http://localhost:4317 \
    --introspection-metadata {{ METADATA_PATH }} \
    --authn-config-path static/auth/noauth_config_v3.json \
    --metadata-path {{ METADATA_PATH }} \
    --enable-sql-interface \
    --expose-internal-errors \
    --export-traces-stdout

# run the engine using schema from tests
run METADATA_PATH="static/metadata.json": start-docker-test-deps
    RUST_LOG=DEBUG cargo run --bin engine -- \
    --otlp-endpoint http://localhost:4317 \
    --authn-config-path static/auth/auth_config_v3.json \
    --metadata-path {{ METADATA_PATH }} \
    --expose-internal-errors \
    --export-traces-stdout 
